package stattracker;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/*
 * Things to add:
 * Options that control which tab is displayed and when
 * More tabs for things like specific playlists like Slayer, MLG, Doubles, etc.
 * More achievements and have the achievmenet interface as a sub tabbedpane within the main tabbedpane
 * 
 */
@SuppressWarnings("serial")
public class Halo3Frame extends JFrame 
{
	private Halo3Data data;
	private JPanel allGames, matchGames, customGames, forgeGames,
					searchGames, profile, customsProfile, playlists, achievements, players;
	private JTabbedPane contentPane;
	
	public Halo3Frame(Halo3Data playerData)
	{
		super("Halo 3 Data for " + playerData.getGamertag());
		//When it closes the memory gets deallocated
		addWindowListener(new WindowAdapter(){
			public void windowClosing(WindowEvent e){
				dispose();
				data = null;
				allGames = null;
				matchGames = null;
				customGames = null;
				forgeGames = null;
				searchGames = null;
				profile = null;
				customsProfile = null;
				playlists = null;
				achievements = null;
				players = null;
				contentPane = null;
				System.gc();
			}
		});
		setBackground(Color.BLACK);
		
		data = playerData;
		allGames = new JPanel();
		matchGames = new JPanel();
		customGames = new JPanel();
		forgeGames = new JPanel();
		searchGames = new JPanel();
		profile = new JPanel();
		customsProfile = new JPanel();
		playlists = new JPanel();
		achievements = new JPanel();
		players = new JPanel();
		contentPane = new JTabbedPane();
		contentPane.setBackground(Color.BLACK);
		contentPane.setForeground(Color.WHITE);
		
		prepGamePanels();
		setGamePanels();
		setSearch();
		setProfiles();
		setPlaylistPanel();
		setAchievements();
		setPlayers();
		
		addTabs();
		JPanel holder = new JPanel(new GridLayout(1,1));
		holder.setBackground(Color.BLACK);
		holder.add(contentPane);
		setContentPane(holder);
		
		setPreferredSize(new Dimension(1050, 1000));
		pack();
		setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth()/2-getSize().width/2, //Centers Width
				(int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()/2-getSize().height/2); //Centers Height
		setVisible(true);
	}
	
	private void setPlayers()
	{
		players.setBackground(Color.BLACK);
		ArrayList<String> playedWith = data.getHalo3Stats().getSortedPlayers();
		players.setLayout(new BoxLayout(players, BoxLayout.PAGE_AXIS));
		addPlayerStats(playedWith.size());
		
		for(int i = 0; i < playedWith.size() && i < 1000; i++)
		{
			if(!playedWith.get(i).equals(data.getGamertag()))
			{
				players.add(formatPlayer(playedWith.get(i)));
				players.add(Box.createRigidArea(new Dimension(0, 3)));
			}
		}
	}
	
	private void addPlayerStats(int totalPlayers)
	{
		JPanel stats = new JPanel();
		stats.setBackground(Color.BLACK);
		
		JLabel label = new JLabel("Total # of unique Gamertags: " + totalPlayers);
		label.setBackground(Color.BLACK);
		label.setForeground(Color.WHITE);
		label.setFont(new Font("Serif", Font.PLAIN, 18));
		
		stats.add(label);
		stats.setBorder(BorderFactory.createLineBorder(Color.WHITE));
		
		players.add(stats);
		players.add(Box.createRigidArea(new Dimension(0, 3)));
	}
	
	private JPanel formatPlayer(String player)
	{
		JPanel p = new JPanel();
		p.setBackground(Color.BLACK);
		
		JLabel label = new JLabel(player + ", played with " + data.getHalo3Stats().getMappedPlayers().get(player) + " times.");
		label.setBackground(Color.BLACK);
		label.setForeground(Color.WHITE);
		label.setFont(new Font("Serif", Font.PLAIN, 16));
		
		p.add(label);
		p.setBorder(BorderFactory.createLineBorder(Color.WHITE, 2));
		
		return p;
	}
	
	private void setAchievements()
	{
		achievements.setBackground(Color.BLACK);
		Halo3Achievements ach = data.getHalo3Stats().getAchievements();
		ArrayList<Achievement> achieved = new ArrayList<Achievement>(ach.getAchievements().values());
		Collections.sort(achieved);
		achievements.setLayout(new BoxLayout(achievements, BoxLayout.PAGE_AXIS));
		SaveComponentListener saver = new SaveComponentListener(achievements, this);
		
		for(Achievement a : achieved)
		{
			achievements.add(formatAchievement(a, saver));
			achievements.add(Box.createRigidArea(new Dimension(0, 3)));
		}
	}
	
	private JPanel formatAchievement(Achievement a, SaveComponentListener saver)
	{
		JPanel ach = new JPanel();
		ach.setBackground(Color.BLACK);
		ach.setForeground(Color.WHITE);
		FlowLayout layout = new FlowLayout();
		layout.setHgap(4);  layout.setVgap(3); layout.setAlignment(FlowLayout.LEFT);
		ach.setLayout(layout);
		String imgLoc = a.getImagePath();
		ImageIcon icon = MyUtils.createImageIcon(imgLoc, a.getTitle());
		JLabel label = new JLabel(icon);
		label.setBorder(BorderFactory.createMatteBorder(1,1,1,1,Color.WHITE));
		ach.add(label);
		label = new JLabel(a.getTitle());
		label.setBackground(Color.BLACK);
		label.setForeground(Color.WHITE);
		label.setFont(new Font("Serif", Font.BOLD, 22));
		JPanel text = new JPanel();
		text.setBackground(Color.BLACK);
		text.setForeground(Color.WHITE);
		text.setLayout(new BoxLayout(text, BoxLayout.PAGE_AXIS));
		text.add(label);
		label = new JLabel(a.getDescription());
		label.setBackground(Color.BLACK);
		label.setForeground(Color.WHITE);
		label.setFont(new Font("Serif", Font.PLAIN, 16));
		text.add(label);
		ach.add(text);
		//if(a.isUnlocked())
			//ach.add(urlButton(a.getGameURL()));
		//ach.setBorder(BorderFactory.createLineBorder(Color.WHITE, 2));
		JPanel test = new JPanel();
		test.setBackground(Color.BLACK);
		test.setLayout(new BorderLayout());
		test.add(ach, BorderLayout.LINE_START);
		if(a.isUnlocked())
			test.add(urlButton(a.getGameURL(), true), BorderLayout.LINE_END);
		test.setBorder(BorderFactory.createLineBorder(Color.WHITE, 2));
		test.addMouseListener(saver);
		return test;
	}
	
	private void setSearch()
	{
		JPanel statResult = new JPanel();
		JPanel medalResult = new JPanel();
		JPanel weaponResult = new JPanel();
		statResult.setBackground(Color.BLACK);
		medalResult.setBackground(Color.BLACK);
		weaponResult.setBackground(Color.BLACK);
		statResult.setLayout(new BorderLayout());
		medalResult.setLayout(new BorderLayout());
		weaponResult.setLayout(new BorderLayout());
		
		searchGames.setLayout(new BoxLayout(searchGames, BoxLayout.PAGE_AXIS));
		searchGames.setBackground(Color.BLACK);
		//Stat Search
		JPanel statSearch = new JPanel();
		statSearch.setBackground(Color.BLACK);
		
		final String[] stats = new String[]{"Kills", "Deaths", "Assists", "K/D"};
		JComboBox comboBox = new JComboBox(stats);
		
		JSpinner spin = new JSpinner(new SpinnerNumberModel(1, 0, 100, 1));
		spin.setBackground(Color.BLACK);
		spin.setForeground(Color.WHITE);
		
		JCheckBox checkBox = new JCheckBox(" Include Customs ", true);
		checkBox.setBackground(Color.BLACK);
		checkBox.setForeground(Color.WHITE);
		
		JButton search = new JButton("Search");
		search.setBackground(Color.WHITE);
		search.setForeground(Color.BLACK);
		search.addActionListener(new mySearchListener(SearchCategory.STATS, comboBox, spin, checkBox, statResult));
		
		statSearch.add(new MyLabel("Search Game Stats For: "));
		statSearch.add(comboBox);
		statSearch.add(new MyLabel(" Amount: "));
		statSearch.add(spin);
		statSearch.add(checkBox);
		statSearch.add(search);
		searchGames.add(statSearch);
		searchGames.add(statResult);
		//Medal Search
		JPanel medalSearch = new JPanel();
		medalSearch.setBackground(Color.BLACK);
		
		MedalListUpdater helper = new MedalListUpdater();
		ArrayList<Medal> names = helper.getMedalList();
		Collections.sort(names, new MedalNameComparator());
		final String[] medals = new String[names.size()];
		for(int i = 0; i < names.size(); i++)
			medals[i] = names.get(i).getName();
		comboBox = new JComboBox(medals);
		
		spin = new JSpinner(new SpinnerNumberModel(1, 0, 100, 1));
		spin.setBackground(Color.BLACK);
		spin.setForeground(Color.WHITE);
		
		checkBox = new JCheckBox(" Include Customs ", true);
		checkBox.setBackground(Color.BLACK);
		checkBox.setForeground(Color.WHITE);
		
		search = new JButton("Search");
		search.setBackground(Color.WHITE);
		search.setForeground(Color.BLACK);
		search.addActionListener(new mySearchListener(SearchCategory.MEDALS, comboBox, spin, checkBox, medalResult));
		
		medalSearch.add(new MyLabel("Search Medals For: "));
		medalSearch.add(comboBox);
		medalSearch.add(new MyLabel(" Amount: "));
		medalSearch.add(spin);
		medalSearch.add(checkBox);
		medalSearch.add(search);
		searchGames.add(medalSearch);
		searchGames.add(medalResult);
		//Weapon Search
		JPanel weaponSearch = new JPanel();
		weaponSearch.setBackground(Color.BLACK);
		
		WeaponListUpdater whelper = new WeaponListUpdater();
		ArrayList<Weapon> wnames = whelper.getWeapList();
		Collections.sort(wnames, new WeaponNameComparator());
		final String[] weapons = new String[wnames.size()];
		for(int i = 0; i < wnames.size(); i++)
			weapons[i] = wnames.get(i).getName();
		comboBox = new JComboBox(weapons);
		
		spin = new JSpinner(new SpinnerNumberModel(1, 0, 100, 1));
		spin.setBackground(Color.BLACK);
		spin.setForeground(Color.WHITE);
		
		checkBox = new JCheckBox(" Include Customs ", true);
		checkBox.setBackground(Color.BLACK);
		checkBox.setForeground(Color.WHITE);
		
		search = new JButton("Search");
		search.setBackground(Color.WHITE);
		search.setForeground(Color.BLACK);
		search.addActionListener(new mySearchListener(SearchCategory.WEAPONS, comboBox, spin, checkBox, weaponResult));
		
		weaponSearch.add(new MyLabel("Search Weapons For: "));
		weaponSearch.add(comboBox);
		weaponSearch.add(new MyLabel(" Amount: "));
		weaponSearch.add(spin);
		weaponSearch.add(checkBox);
		weaponSearch.add(search);
		searchGames.add(weaponSearch);
		searchGames.add(weaponResult);
	}
	
	class mySearchListener implements ActionListener
	{
		SearchCategory category;
		JComboBox searchFor;
		JSpinner amt;
		JCheckBox customsIncluded;
		JPanel result;
		public mySearchListener(SearchCategory category, JComboBox what, JSpinner amount, JCheckBox customs, JPanel results)
		{
			this.category = category;
			searchFor = what;
			amt = amount;
			customsIncluded = customs;
			result = results;
		}
		
		public void actionPerformed(ActionEvent e)
		{
			result.removeAll();
			search(category, (String)searchFor.getSelectedItem(), (Integer)amt.getValue(), customsIncluded.getSelectedObjects() != null, result);
			
			result.repaint();
			searchGames.repaint();
			contentPane.repaint();
		}
	}
	
	private void search(SearchCategory cat, String whatFor, int amt, boolean customs, JPanel result)
	{
		ArrayList<Halo3GameData> exact = new ArrayList<Halo3GameData>();
		ArrayList<Halo3GameData> possibles = new ArrayList<Halo3GameData>();
		ArrayList<Halo3GameData> searching;
		searching = (customs ? data.getHalo3Stats().getAllGames() : data.getHalo3Stats().getMatchmadeGames());
		
		for(Halo3GameData g : searching)
		{
			if(cat == SearchCategory.STATS)
			{
				if(whatFor.equals("Kills"))
				{
					if(g.getDetail().getKills() > amt)
						possibles.add(g);
					if(g.getDetail().getKills() == amt)
						exact.add(g);
				}
				else if(whatFor.equals("Deaths"))
				{
					if(g.getDetail().getDeaths() > amt)
						possibles.add(g);
					if(g.getDetail().getDeaths() == amt)
						exact.add(g);
				}
				else if(whatFor.equals("Assists"))
				{
					if(g.getDetail().getAssists() > amt)
						possibles.add(g);
					if(g.getDetail().getAssists() == amt)
						exact.add(g);
				}
				else if(whatFor.equals("K/D"))
				{
					if(g.getDetail().getKills() > 0)
					{
						if(g.getDetail().getDeaths() == 0)
						{
							if(g.getDetail().getKills() >= amt)
								possibles.add(g);
						}
						else
						{
							int kd = g.getDetail().getKills() / g.getDetail().getDeaths();
							if(kd > amt)
								possibles.add(g);
							if(kd == amt)
								exact.add(g);
						}
					}
				}
			}
			else if(cat == SearchCategory.MEDALS)
			{
				for(Medal m : g.getDetail().getMedals())
				{
					if(m.getName().equals(whatFor))
					{
						if(m.getMedalCount() > amt)
							possibles.add(g);
						if(m.getMedalCount() == amt)
							exact.add(g);
					}
				}
			}
			else
			{
				for(Weapon w : g.getDetail().getWeapons())
				{
					if(w.getName().equals(whatFor))
					{
						if(w.getKillCount() > amt)
							possibles.add(g);
						if(w.getKillCount() == amt)
							exact.add(g);
					}
				}
			}
		}
		
		JPanel results = new JPanel();
		results.setLayout(new BoxLayout(results, BoxLayout.PAGE_AXIS));
		results.setBackground(Color.BLACK);
		int gamesAdded = 0;
		
		while((exact.size() + possibles.size()) < 5)
			possibles.add(Halo3GameData.getBlank());
		
		for(Halo3GameData g : exact)
		{
			if(gamesAdded < 1000)
			{
				results.add(getGamePanel(g));
				results.add(Box.createRigidArea(new Dimension(0, 2)));
				gamesAdded++;
			}
		}
		
		for(Halo3GameData g : possibles)
		{
			if(gamesAdded < 1000)
			{
				results.add(getGamePanel(g));
				results.add(Box.createRigidArea(new Dimension(0, 2)));
				gamesAdded++;
			}
		}
		
		JScrollPane scroller = MyUtils.makeScroll(results);
		scroller.setPreferredSize(new Dimension(scroller.getWidth(), 100));
		result.add(scroller, BorderLayout.CENTER);
		result.setPreferredSize(new Dimension(scroller.getWidth(), 100));
	}
	
	private void setProfiles()
	{
		setProfile(profile, getHeader(false), false);
		setProfile(customsProfile, getHeader(true), true);
	}
	
	private void setProfile(JPanel prof, JPanel header, boolean customs)
	{
		prof.setLayout(new BoxLayout(prof, BoxLayout.PAGE_AXIS));
		Halo3Stats stats = data.getHalo3Stats();
		prof.setBackground(Color.BLACK);
		
		JScrollPane medals = ( customs ? getMedalsPanel(stats.getCustomMedals(), stats.customsPlayed()):
										 getMedalsPanel(stats.getAllMedals(), stats.allPlayed() - stats.forgePlayed()));
		
		JScrollPane weapons = ( customs ? getWeaponsPanel(stats.getCustomWeapons(), stats.getCustomKills()):
										  getWeaponsPanel(stats.getAllWeapons(), stats.getTotalKills()));
		
		JPanel weapsAndMeds = new JPanel();
		weapsAndMeds.setBackground(Color.BLACK);
		weapsAndMeds.setLayout(new BoxLayout(weapsAndMeds, BoxLayout.LINE_AXIS));
		weapsAndMeds.add(weapons);
		weapsAndMeds.add(medals);
		
		prof.add(header);
		prof.add(weapsAndMeds);
		
	}
	
	private JPanel getHeader(boolean custom)
	{
		JPanel header = new JPanel();
		header.setBackground(Color.BLACK);
		addImages(header, data.getImages());
		JPanel info = new JPanel();
		info.setLayout(new BoxLayout(info, BoxLayout.PAGE_AXIS));
		info.setBackground(Color.BLACK);
		addPlayerData(info, data.getImages(), custom);
		addPlayerStats(info, custom);
		info.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.WHITE));
		header.add(info);
		header.addMouseListener(new SaveComponentListener(header, this));
		return header;
	}
	
	private void addPlayerData(JPanel panel, Halo3User user, boolean custom)
	{
		Halo3Stats info = data.getHalo3Stats();
		JPanel data = new JPanel();
		data.setBackground(Color.BLACK);
		data.setLayout(new BoxLayout(data, BoxLayout.PAGE_AXIS));
		MyLabel name = new MyLabel(String.format("%s - %s        %s", user.getGamertag(), user.getServiceTag(), user.getRank()));
		name.setHorizontalAlignment(JLabel.CENTER);
		data.add(name);
		data.add(new MyLabel(String.format("Highest Skill: %d     EXP: %d", user.getSkill(), user.getEXP())));
		if(custom)
		{
			data.add(new MyLabel("Games Played: " + info.customsPlayed()));
			data.add(new MyLabel("Time Played: " + MyUtils.formatTime(info.getCustomTime()) + " "));
		}
		else
		{
			data.add(new MyLabel(String.format("Games Played: %d ( Matchmade: %d Custom: %d Forge: %d ) ",	
												info.allPlayed(), info.matchPlayed(), info.customsPlayed(), info.forgePlayed())));
			data.add(new MyLabel("Time Played: " + MyUtils.formatTime(info.getTotalTime()) + " "));
		}
		data.add(Box.createRigidArea(new Dimension(0, 2)));
		data.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.WHITE));
		data.add(Box.createRigidArea(new Dimension(0, 2)));
		panel.add(data);
	}
	
	private void addPlayerStats(JPanel panel, boolean custom)
	{
		Halo3Stats info = data.getHalo3Stats();
		if(custom)
		{
			panel.add(new MyLabel(String.format("Kills: %d  Deaths: %d  Assists: %d    K/D: %.3f    K.P.G. %.2f  ",
					info.getCustomKills(), info.getCustomDeaths(), info.getCustomAssists(), 
					(double)info.getCustomKills() / info.getCustomDeaths(), (double) info.getTotalKills() / info.customsPlayed())));
			String percentages = String.format("Sniper Headshot Rate: %.2f", info.getCustomSniperPercentage()) + "%    ";
			percentages += String.format("Sticky Rate: %.2f", info.getCustomStickyPercentage()) + "%";
			panel.add(new MyLabel(percentages));
		}
		else
		{
			panel.add(new MyLabel(String.format("Kills: %d  Deaths: %d  Assists: %d    K/D: %.3f    K.P.G. %.2f  ",
					info.getTotalKills(), info.getTotalDeaths(), info.getTotalAssists(), 
					(double)info.getTotalKills() / info.getTotalDeaths(), (double) info.getTotalKills() / (info.allPlayed() - info.forgePlayed()))));
			String percentages = String.format("Sniper Headshot Rate: %.2f", info.getSniperPercentage()) + "%    ";
			percentages += String.format("Sticky Rate: %.2f", info.getStickyPercentage()) + "%";
			panel.add(new MyLabel(percentages));
		}
	}
	
	private void addImages(JPanel panel, Halo3User images)
	{
		panel.add(new JLabel(images.getModel().getIcon()));
		JPanel small = new JPanel();
		small.setBackground(Color.BLACK);
		small.setLayout(new BoxLayout(small, BoxLayout.PAGE_AXIS));
		small.add(new JLabel(images.getEmblem().getIcon()));
		small.add(new JLabel(images.getBadge().getIcon()));
		small.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.WHITE));
		panel.add(small);
	}
	
	private JScrollPane getWeaponsPanel(ArrayList<Weapon> weapons, int totalKills)
	{
		JPanel arrangement = new JPanel();
		arrangement.setLayout(new BoxLayout(arrangement, BoxLayout.PAGE_AXIS));
		arrangement.setBackground(Color.BLACK);
		SaveComponentListener saver = new SaveComponentListener(arrangement, this);
		for(Weapon w : weapons)
		{
			if(w.getKillCount() > 0)
			{
				ImageIcon icon = MyUtils.createImageIcon(w.getImgLoc(), w.getName());
				JLabel label = new JLabel("Kills: " + w.getKillCount() + String.format(" (%.2f", ((double) w.getKillCount() / totalKills) * 100) + "%)", icon, JLabel.LEFT);
				label.setFont(new Font("Serif", Font.PLAIN, 16));
				label.setToolTipText(w.getName());
				label.setForeground(Color.WHITE);
				label.setVerticalTextPosition(JLabel.CENTER);
				label.setHorizontalTextPosition(JLabel.RIGHT);
				label.addMouseListener(saver);
				arrangement.add(label);
			}
		}
		
		return MyUtils.makeScroll(arrangement);
	}
	
	private JScrollPane getMedalsPanel(ArrayList<Medal> medals, int gamesPlayed)
	{
		JPanel arrangement = new JPanel();
		arrangement.setBackground(Color.BLACK);
		arrangement.setForeground(Color.WHITE);
		arrangement.setLayout(new BoxLayout(arrangement, BoxLayout.PAGE_AXIS));
		SaveComponentListener saver = new SaveComponentListener(arrangement, this);
		arrangement.addMouseListener(saver);
		
		JPanel panelBnet = new JPanel();
		JPanel panelSpree = new JPanel();
		JPanel panelMultikill = new JPanel();
		JPanel panelWeaponSpree = new JPanel();
		JPanel panelObjectiveSpree = new JPanel();
		JPanel panelStyle = new JPanel();
		JPanel panelHelpful = new JPanel();
		JPanel panelObjective = new JPanel();
		
		panelBnet.setBackground(Color.BLACK);
		panelSpree.setBackground(Color.BLACK);
		panelMultikill.setBackground(Color.BLACK);
		panelWeaponSpree.setBackground(Color.BLACK);
		panelObjectiveSpree.setBackground(Color.BLACK);
		panelStyle.setBackground(Color.BLACK);
		panelHelpful.setBackground(Color.BLACK);
		panelObjective.setBackground(Color.BLACK);
		
		for(Medal m : medals)
		{
			ImageIcon icon = MyUtils.createImageIcon(m.getImgLoc(), m.getName());
			int amount = m.getMedalCount();
			JLabel label = new JLabel((amount == 0 ? "---" : amount+""), icon, JLabel.CENTER);
			label.setFont(new Font("Serif", Font.PLAIN, 16));
			label.setToolTipText(String.format("%s: %.3f per Game", m.getName(), (double)m.getMedalCount()/gamesPlayed));
			label.setForeground(Color.WHITE);
			label.setVerticalTextPosition(JLabel.BOTTOM);
			label.setHorizontalTextPosition(JLabel.CENTER);
			label.addMouseListener(saver);
			
			if(m.getImgLoc().contains("Bnet"))
				panelBnet.add(label);
			else if(m.getImgLoc().contains("Spree/Objective"))
				panelObjectiveSpree.add(label);
			else if(m.getImgLoc().contains("Spree/Weapon"))
				panelWeaponSpree.add(label);
			else if(m.getImgLoc().contains("Spree"))
				panelSpree.add(label);
			else if(m.getImgLoc().contains("Style"))
				panelStyle.add(label);
			else if(m.getImgLoc().contains("Objective"))
				panelObjective.add(label);
			else if(m.getImgLoc().contains("Multikill"))
				panelMultikill.add(label);
			else
				panelHelpful.add(label);
		}
		
		arrangement.add(panelBnet);
		arrangement.add(panelSpree);
		arrangement.add(panelWeaponSpree);
		arrangement.add(panelMultikill);
		arrangement.add(panelStyle);
		arrangement.add(panelHelpful);
		arrangement.add(panelObjective);
		arrangement.add(panelObjectiveSpree);
		arrangement.setBorder(BorderFactory.createLineBorder(Color.WHITE));
		return new JScrollPane(arrangement, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
	}
	
	private void setPlaylistPanel()
	{
		playlists.setBackground(Color.BLACK);
		playlists.setLayout(new BoxLayout(playlists, BoxLayout.PAGE_AXIS));
		SaveComponentListener saver = new SaveComponentListener(playlists, this);
		for(Playlist p : data.getHalo3Stats().getPlaylists())
		{
			formatPlaylist(p, saver);
			playlists.add(Box.createRigidArea(new Dimension(0, 4)));
		}
	}
	
	private void formatPlaylist(Playlist p, SaveComponentListener saver)
	{
		JPanel list = new JPanel();
		list.setBackground(Color.BLACK);
		list.setForeground(Color.WHITE);
		list.setLayout(new GridLayout(4, 1));
		list.add(formatPlaylistTitle(p));
		MyLabel label;
		
		label = new MyLabel(String.format("     Wins: %d   Losses: %d   Time Played: %s", p.getWins(), p.getLosses(), MyUtils.formatTime(p.getTime())));
		list.add(label);
		
		label = new MyLabel(String.format("     Kills: %d   Deaths: %d   Assists: %d  K.P.G: %.3f   K/D: %.3f", 
											p.getKills(), p.getDeaths(), p.getAssists(), p.getAvgKill(), ((double) p.getKills()/p.getDeaths())));
		list.add(label);
		
		label = new MyLabel(String.format("     Expect to get between %.2f and %.2f kills and between %.2f and %.2f deaths in this playlist.",
							p.getAvgKill() - p.getSDKill(), p.getAvgKill() + p.getSDKill(), p.getAvgDeath() - p.getSDDeath(), p.getAvgDeath() + p.getSDDeath()));
		list.add(label);
		
		list.setBorder(BorderFactory.createMatteBorder(2, 2, 2, 2, Color.WHITE));
		list.addMouseListener(saver);
		playlists.add(list);
	}
	
	private JLabel formatPlaylistTitle(Playlist p)
	{
		MyLabel title = new MyLabel();
		title.setFont(new Font("Arial", Font.BOLD, 14));
		String exampleGames = "";
		ArrayList<Halo3GameData> games = p.getGames();
		for(int i = games.size()-1; (i >= 0 && i >= games.size()-2); i--)
		{
			exampleGames += games.get(i).getInfo().getGameType() + " on " + games.get(i).getInfo().getMap() + " or ";
		}
		exampleGames = exampleGames.substring(0, exampleGames.length()-4);
		String currentRank = "";
		if(p.isRanked())
			currentRank = "   Current Rank: " + games.get(games.size()-1).getDetail().getRank();
		title.setText("  " + p.getTitle() + " (e.g. " + exampleGames + ") Last Played " + games.get(games.size()-1).getInfo().getDate() + currentRank);
		title.setHorizontalTextPosition(JLabel.LEFT);
		title.setBorder(BorderFactory.createMatteBorder(0,0,1,0, Color.WHITE));
		return title;
	}
	
	private void setGamePanels()
	{
		setGamePanel(data.getHalo3Stats().getAllGames(), allGames);
		setGamePanel(data.getHalo3Stats().getMatchmadeGames(), matchGames);
		setGamePanel(data.getHalo3Stats().getCustomGames(), customGames);
		setGamePanel(data.getHalo3Stats().getForgeGames(), forgeGames);
	}
	
	private void setGamePanel(ArrayList<Halo3GameData> games, JPanel panel)
	{
		panel.setBackground(Color.BLACK);
		for(int i = games.size()-1; (i >= 0 && i >= games.size()-101); i--)
		{
			panel.add(getGamePanel(games.get(i)));
			panel.add(Box.createRigidArea(new Dimension(0, 2)));
		}
	}
	
	private JPanel getGamePanel(Halo3GameData g)
	{
		JPanel game = new JPanel(new GridLayout(2, 6));
		game.setBackground(Color.BLACK);
		if(!g.getInfo().getGameType().equals(""))
		{
			game.add(gameLabel(g.getInfo().getGameType()));
			game.add(gameLabel(" " + g.getInfo().getDate()));
			game.add(gameLabel(g.getInfo().getMap()));
			game.add(gameLabel(g.getInfo().getPlaylist()));
			game.add(gameLabel(g.getInfo().getPlacement()));
			game.add(urlButton(g.getInfo().getURL(), false));
			game.add(gameDataLabel("Kills: "+ g.getDetail().getKills()));
			game.add(gameDataLabel("Deaths: " + g.getDetail().getDeaths()));
			game.add(gameDataLabel("Assists: " + g.getDetail().getAssists()));
			game.add(topWeapon(g));
			int totalMed = 0;
			for(Medal m : g.getDetail().getMedals())
				totalMed += m.getMedalCount();
			game.add(gameDataLabel("Total Medals: " + totalMed));
			game.add(topMedals(g));
		}
		else
		{
			game.add(gameLabel(g.getInfo().getGameType()));
			game.add(gameLabel(" " + g.getInfo().getDate()));
			game.add(gameLabel(g.getInfo().getMap()));
			game.add(gameLabel(g.getInfo().getMap()));
			game.add(gameLabel(g.getInfo().getPlacement()));
			game.add(urlButton("http://www.bungie.net", false));
			game.add(gameLabel(""));
			game.add(gameLabel(""));
			game.add(gameLabel(""));
			game.add(gameLabel(""));
			game.add(gameLabel(""));
			game.add(gameLabel(""));
		}
		return game;
	}
	
	private MyLabel gameDataLabel(String g)
	{
		MyLabel game = new MyLabel("  " + g);
		game.setFont(new Font("Arial", Font.ITALIC, 12));
		game.setBorder(BorderFactory.createMatteBorder(1, 1, 2, 1, Color.WHITE));
		return game;
	}
	private MyLabel gameLabel(String g)
	{
		MyLabel game = new MyLabel("  " + g);
		game.setBorder(BorderFactory.createMatteBorder(2, 1, 1, 1, Color.WHITE));
		return game;
	}
	
	private void prepGamePanels()
	{
		allGames.setLayout(new BoxLayout(allGames, BoxLayout.PAGE_AXIS));
		addGamePanelHeader(allGames);
		matchGames.setLayout(new BoxLayout(matchGames, BoxLayout.PAGE_AXIS));
		addGamePanelHeader(matchGames);
		customGames.setLayout(new BoxLayout(customGames, BoxLayout.PAGE_AXIS));
		addGamePanelHeader(customGames);
		forgeGames.setLayout(new BoxLayout(forgeGames, BoxLayout.PAGE_AXIS));
		addGamePanelHeader(forgeGames);
	}
	
	private void addGamePanelHeader(JPanel panel)
	{
		JPanel header = new JPanel(new GridLayout(2, 6));
		header.setBackground(Color.BLACK);
		header.add(gameLabel("Game Type"));
		header.add(gameLabel("Date"));
		header.add(gameLabel("Map"));
		header.add(gameLabel("Playlist"));
		header.add(gameLabel("Place"));
		header.add(gameLabel("URL"));
		
		header.add(gameDataLabel("Kills"));
		header.add(gameDataLabel("Deaths"));
		header.add(gameDataLabel("Assists"));
		header.add(gameDataLabel("Tool of Destruction"));
		header.add(gameDataLabel("Medals"));
		header.add(gameDataLabel("Top Medals"));
		
		panel.add(header);
		panel.add(Box.createRigidArea(new Dimension(0, 2)));
	}
	
	//Should be called after all panels are built and everything is ready to display
	
	private void addTabs()
	{
		contentPane.addTab("All", MyUtils.makeScroll(allGames));
		if(data.getHalo3Stats().matchPlayed() != 0)
			contentPane.addTab("Matchmaking", MyUtils.makeScroll(matchGames));
		if(data.getHalo3Stats().customsPlayed() != 0)
			contentPane.addTab("Custom Games", MyUtils.makeScroll(customGames));
		if(data.getHalo3Stats().forgePlayed() != 0)
			contentPane.addTab("Forge", MyUtils.makeScroll(forgeGames));
		contentPane.addTab("Search", searchGames);
		contentPane.addTab("Profile", profile);
		if(data.getHalo3Stats().customsPlayed() != 0)
			contentPane.addTab("Customs Only", customsProfile);
		contentPane.addTab("Playlists", MyUtils.makeScroll(playlists));
		contentPane.addTab("Achievements", MyUtils.makeScroll(achievements));
		contentPane.addTab("Players", MyUtils.makeScroll(players));
	}
	
	private JButton urlButton(String url, boolean big)
	{
		final String web = url;
		JButton newButton = new JButton("Bungie.net");
		String imgPath = "";
		if(big)
			imgPath = "MedalIcons/bungieBig.gif";
		else
			imgPath = "MedalIcons/bungieLogoSmall.jpg";
		ImageIcon icon = MyUtils.createImageIcon(imgPath,"");
		newButton = new JButton(icon);
		newButton.setMargin(new Insets(0,0,0,0));
		newButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e)
			{
				invokeBrowser(web);
			}
			//Should launch any web browser if available
			@SuppressWarnings("unchecked")
			public final boolean invokeBrowser(String url) 
			{
				String osName = System.getProperty("os.name");
				try {
					if (osName.startsWith("Mac OS")) 
					{
						Class fileMgr = Class.forName("com.apple.eio.FileManager");
						Method openURL = fileMgr.getDeclaredMethod("openURL",
								new Class[] {String.class});
						openURL.invoke(null, new Object[] {url});
					}
					else if (osName.startsWith("Windows"))
						Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
					else 
					{ //assume Unix or Linux
						String[] browsers = {
								"firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" };
						String browser = null;
						for (int count = 0; count < browsers.length && browser == null; count++)
							if (Runtime.getRuntime().exec(
									new String[] {"which", browsers[count]}).waitFor() == 0)
								browser = browsers[count];
						if (browser == null)
							throw new Exception("Could not find web browser");
						else
							Runtime.getRuntime().exec(new String[] {browser, url});
					}
				}
				catch (Exception e) {
					String errMsg = "Failed to launch any web browser";
					JOptionPane.showMessageDialog(null, errMsg + ":\n" + e.getLocalizedMessage());
				}
				return true;
			}
		});
		return newButton;
	}
	
	private JPanel topMedals(Halo3GameData g)
	{
		JPanel meds = new JPanel();
		meds.setBackground(Color.BLACK);
		ArrayList<Medal> earned = g.getDetail().getMedals();
		if(earned.size() > 0)
		{
			Collections.sort(earned);
			for(int i = 0; (i < 5 && i < earned.size()); i++)
			{
				meds.add(miniMedal(earned.get(i)));
			}
		}
		else
		{
			JLabel l = new JLabel("_____");
			l.setForeground(Color.WHITE);
			meds.add(l);
		}
		meds.setBorder(BorderFactory.createMatteBorder(1, 1, 2, 1, Color.WHITE));
		return meds;
	}
	
	private JLabel miniMedal(Medal m)
	{
		String miniLoc = m.getImgLoc().substring(0,m.getImgLoc().length()-4) + "mini.gif";
		if(m.getImgLoc().equals(""))
			miniLoc = "MedalIcons/Weapons/Errormini.gif";
		ImageIcon icon = MyUtils.createImageIcon(miniLoc, "");
		JLabel label = new JLabel(icon);
		label.setToolTipText(m.getName() + " got " + m.getMedalCount());
		return label;
	}
	
	private JPanel topWeapon(Halo3GameData g)
	{
		JPanel p = new JPanel();
		p.setBackground(Color.BLACK);
		ArrayList<Weapon> used = g.getDetail().getWeapons(); 
		if(used.size() > 0)
		{
			Collections.sort(used);
			p.add(miniWeapon(used.get(0)));
		}
		else
		{
			JLabel l = new JLabel("_____");
			l.setForeground(Color.BLACK);
			p.add(l);
		}
		p.setBorder(BorderFactory.createMatteBorder(1, 1, 2, 1, Color.WHITE));
		return p;
	}
	
	private JLabel miniWeapon(Weapon w)
	{
		//System.out.println(w.name);
		String miniLoc = w.getImgLoc().substring(0,w.getImgLoc().length()-4) + "mini.gif";
		ImageIcon icon = MyUtils.createImageIcon(miniLoc, "");
		JLabel label = new JLabel(icon);
		label.setToolTipText(w.getName() + ": got " + w.getKillCount() + " kills");
		return label;
	}
}

enum SearchCategory
{
	STATS, MEDALS, WEAPONS
}

class MedalNameComparator implements Comparator<Medal>
{
	public int compare(Medal one, Medal two)
	{
		return one.getName().compareTo(two.getName());
	}
}

class WeaponNameComparator implements Comparator<Weapon>
{
	public int compare(Weapon one, Weapon two)
	{
		return one.getName().compareTo(two.getName());
	}
}
